#!/usr/bin/env python
"""
Checks for a list of status codes and a list of 
websites to see if they are running or giving problems.

A list of sites should be in the same directory as this script.
The sites should have a full http address like:
http://example.com

The name of the file should be "config.ini"

This script would then take line by line, all the addresses 
in the file and check them.

Alfredo Deza @ 2009
"""

import sys
# Without this, webstatus won't be able to find other
# resources to import
sys.path.append('/etc/webstatus')

import urllib2
import os
from mailer import mailer
from subprocess import Popen
import optparse, subprocess, sys, time
from signal import SIGTERM
from dbwork import DataBase

# List of error codes we are interested in.
# Note how 401 is not here
errorcodes =  [400, 402, 403, 404, 405, 406, 407, 408, 409, 410, 
                411, 412, 413, 414, 415, 416, 417, 500, 501, 502,
                503, 504, 505, 506, 507, 508, 509]

# Will parse the config.ini and append the sites here
websites = []

# All the errors will be appended to this list
errors_list = []

# All the sites that have issues
problem_sites = []

def start():
    """
    Double forks the process in the background
    to avoid zombies and writes the pid
    in /var/run/name.pid
    """
    daemon = "/var/run/webstatus.pid"
    print "Starting the webstatus daemon."
    sys.stdout.flush()
    sys.stderr.flush()
    try:
        pid = os.fork()
        if pid > 0:
            sys.exit(0)
    except OSError, exc:
        sys.exit("%s: fork #1 failed: (%d) %s\n" % (sys.argv[0],
        exc.errno, exc.strerror))

    os.chdir("/")
    os.umask(0)
    os.setsid()

    try:
        pid = os.fork()
        if pid > 0:
            sys.exit(0)
    except OSError, exc:
        sys.exit("%s: fork #2 failed: (%d) %s\n" % (sys.argv[0],
        exc.errno, exc.strerror))
    pid_file =  open(daemon, "w")
    pid = str(os.getpid())
    print pid
    pid_file.write(pid+"\n")
    pid_file.close
    #Lets try to write to a log file:
    stdin = "/var/log/webstatus/log"
    stdout = "/var/log/webstatus/log"
    stderr = "/var/log/webstatus/log"
    si = open(stdin, 'r')
    so = open(stdout, 'a+')
    se = open(stderr, 'a+', 0)
    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())

def stop():
    """
    Stops the running process with the
    corresponding pid.
    """
    daemon = "/var/run/webstatus.pid"
    print "Stopping the webstatus daemon"
    pidfile = open(daemon, "r")
    pid = pidfile.readline()
    print "With pid number %s" % pid
    os.kill(int(pid), SIGTERM)
    remove = "rm -f /var/run/webstatus.pid"
    subprocess.call(remove, shell=True)

def spawn(website):
    """calls subwebstatus with a domain"""
    command = "/etc/webstatus/subwebstatus %s" % website
    Popen(command, shell=True)

def check_error_domains():
    """Checks websites[] with database to avoid re-sending alerts"""
    for line in dbwork.query():
        for site in websites:
            if line[0] == site:
                websites.remove(line[0])

def get_sites():
    """ Parses the config.ini file looking for sites"""
    file = open("/etc/webstatus/config.ini")
    for line in file:
        websites.append(line.strip('\n'))

def errors(website):
    """Iterates the error list against the websites 
    and checks for any problems"""
    try:
        urllib2.urlopen(website)
    except urllib2.HTTPError, e:
        for err in errorcodes:
            if e.code == err:
                error = "\n Url %s gave code %s" % (website, err)
                errors_list.append(error)
                dbwork.insert(website)
                spawn(website)
    except urllib2.URLError, e:
        error = "\n Something went wrong with %s Reason: %s" % (website, e.reason[1])
        errors_list.append(error) 
        dbwork.insert(website)
        spawn(website)

def notify(errors_list, subj):
    """ Sends the email with the information
    gathered about errors """
    user = ""
    passwd = ""
    to = [""]
    subject = subj
    text = errors_list
    mailer(user, passwd, to, subject, text)

def purge():
    """Gets rid of any pending variables before running again"""
    del errors_list[:]
    del problem_sites[:]
    del websites[:]

def daemon():
    """Takes charge of all the daemonizing calls"""
    while True:
        time.sleep(10)
        purge()
        get_sites()
        check_error_domains()
        for i in websites:
            errors(i)
        if errors_list:
            notify('\n'.join(errors_list), "Alert: Site Issues!")

def main():
    p = optparse.OptionParser()
    options, args = p.parse_args()

    if len(args) == 1:
        if args[0] == "start":
            start()
            daemon()
        if args[0] == "stop":
            stop()
    else:
        p.print_help()


if __name__ == '__main__':
    main()
